package game.pong.views.components
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.TimerEvent;
	
	import game.pong.business.Gamespeed;
	import game.pong.events.ScoreEvent;
	import game.pong.events.SoundEvent;
	
	import mx.containers.Canvas;

	public class Ball extends Canvas
	{
		/** Timer to handle the refresh method */		
		private var ticker : Gamespeed = new Gamespeed();
		
		/** The gameArea of the ball (which will give the ball's boundaries) */		
		public var gameArea : DisplayObjectContainer;
		
		/** Velocity in the X direction */
		public var vX : Number = 0;
		
		/** Velocity in the Y direction */
		public var vY : Number = 0;
		
		/** Bouncers the ball collides with paddles */
		public var bouncers : Array;
		
		/** Constructor	 */		
		public function Ball()
		{
			gameArea = this.parent;
			ticker.addEventListener(TimerEvent.TIMER, refresh);
		}
		
		/**
		 * Update the movement of the ball
		 */
		public function refresh(event : Event) : void
		{
			// Update based on velocity
			x += vX;
			y += vY;
			
			// Check if we've gone off the left side (Computer wins)
			if (x < 0)
				updateScore(false);

			// Check if we've gone off the right side (player wins)
			if (x >= gameArea.width)
				updateScore(true);
			
			
			// Check if we've gone off the top or the bottom of the game area
			if (y <= 0 || y >= gameArea.height - this.height)
			{
				// Reverse Y direction and bounce
				vY = -vY;
				y += vY;
				// Dispatch a SoundEvent for the bounce_simple sound
				dispatchEvent(new SoundEvent(SoundEvent.BOUNCE_SIMPLE));
			}
			
			// Check if we hit any of the bouncers. If we did, have it bounce us.
			for (var it : String in bouncers)
			{
				var bouncer : AbstractPaddle = bouncers[it];
				// Check if we hit the current bouncer
				if (hitTestObject(DisplayObject(bouncer)))
				{
					// Bounce off the current bouncer and stop checking
					bouncer.bounce(this);
					break;
				}
			}
		}
		
		/**
		 * Update the score by dispatching a ScoreEvent
		 * @param updateUser
		 */		
		private function updateScore(updateUser : Boolean) : void
		{
			reset();
			var scoreEvent : ScoreEvent = new ScoreEvent(ScoreEvent.UPDATE);
			scoreEvent.updateUser = updateUser;
			dispatchEvent(scoreEvent);
			dispatchEvent(new SoundEvent(SoundEvent.LOST_BALL));
		}
		
		/**
		 * Reset method
		 * @param event
		 */		
		public function reset(event : Event = null) : void
		{
			ticker.resetSpeed();
			x = (gameArea.width - width)/2;
			y = (gameArea.height - height)/2;
			// Serve the ball by giving it a random initial velocity
			vX = (Math.random() % 2 == 0 ? 1 : -1) * 10;
			vY = Math.random() % 5;
			ticker.start();
		}
		
		/**
		 * Start method 
		 * 
		 */		
		public function start() : void
		{
			reset();
			ticker.start();
		} 
		
		/**
		 * Stop method 
		 * 
		 */		
		public function stop() : void
		{
			reset();
			ticker.stop();
		} 
		
	}
}